// Copyright 2009 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Author: Jeff Stewart
// A MultiProbe does DNS resolution.  It then uses the factory to create a
// probe for each record found at that address.  It scrambles the order, and
// runs a "short" probe at all but the last address, where a full probe is
// run.  It looks at the response codes and differentiates the case where
// all the addresses return the same problem vs. the cases where they differ.

#ifndef POPDIAG_PROBES_MULTIPROBE_H__
#define POPDIAG_PROBES_MULTIPROBE_H__

#include <QtCore/QList>
#include <QtNetwork/QHostAddress>
#include <QtNetwork/QHostInfo>

#include "probes/probe.h"

namespace popdiag {

// Each user of MultiProbe must provide a factory that creates an appropriate
// Probe instance for the given IP address.  The MultiProbe will create
// n - 1 probes where do_complete_probe is false and 1 probe where
// do_complete_probe is true.  We will create all n probes, then run them
// serially.
class MultiProbeFactory {
 public:
  virtual Probe *CreateProbe(const QHostAddress &addr,
                             bool do_complete_probe) = 0;
  virtual ~MultiProbeFactory() {}
};

// MultiProbe probes a DNS name and creates a probe for each address.
// You are not expected to subclass MultiProbe, rather you will implement
// MultiProbeFactory to execute probes against each IP address.
class MultiProbe : public Probe {
  Q_OBJECT
 public:

  typedef enum {
    OK = 0,
    RESOLVE_FAILED,
  } MultiProbeFault;

  // Create a multiprobe against dns_name.  The factory will be deleted
  // when this probe is destroyed.
  MultiProbe(const QString &name,
             const QString &dns_name,
             MultiProbeFactory *factory);
  virtual ~MultiProbe();

  // Get a display string describing the results of this probe.
  virtual QString GetDisplayText();

  // Retrieve a numeric representation of this fault.
  // 0 is reserved for "success".  Most other values are probe-specific.
  virtual int GetFaultId();

  // Get a string representation of this probe's class.
  // Can be used with GetFaultId() to construct support urls, though
  // it is not currently used for this.
  virtual QString GetProbeId();

  // Get an HTML blob (possibly large) for inclusion in the report.
  virtual QString DebugText();

  // Fetch progress made in this probe.
  void GetProgress(int *completed, int *estimated_total);

  private slots:
  void OnProgress(int done, int total);
  void OnProbeComplete(ResultStatus r);
  void OnDnsResolutionComplete(const QHostInfo &info);

 protected:
  virtual void StartProbe();

  private slots:
  void CheckForComplete();

 private:
  Probe *GetLongProbe();
  void StartNextProbe();

  scoped_ptr<MultiProbeFactory> factory_;
  const QString dns_name_;
  typedef QList<Probe *> StorageType;
  StorageType probes_;
  StorageType::iterator next_probe_;
  MultiProbeFault fault_;
};

}  // namespace popdiag

#endif  // POPDIAG_PROBES_MULTIPROBE_H__
